home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / symlinks.0 / symlinks / symlinks-1.0 / symlinks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-27  |  5.3 KB  |  252 lines

  1. #include <unistd.h>
  2. #ifndef _POSIX_SOURCE
  3. #define _POSIX_SOURCE
  4. #endif
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #include <sys/param.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/dir.h>
  12. #include <time.h>
  13. #include <stddef.h>
  14. #include <errno.h>
  15.  
  16. #ifndef S_ISLNK
  17. #define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
  18. #endif
  19.  
  20. #ifndef PATH_MAX
  21. #define PATH_MAX 1024
  22. #endif
  23.  
  24. #define progver "%s: scan/change symbolic links - V1.0 - by Mark Lord\n\n"
  25. static char *progname;
  26. static int verbose = 0, fix_links = 0, recurse = 0, delete = 0;
  27.  
  28. /*
  29.  * tidypath removes excess slashes and "." references from a path string
  30.  */
  31. int tidy_path (char *path)
  32. {
  33.     int tidied = 0;
  34.     char *s, *p;
  35.  
  36.     strcat(path,"/");    /* tmp trailing slash simplifies things */
  37.     while (NULL != (p = strstr(path,"/./"))) {
  38.         s = p+2;
  39.         if (p == path)
  40.             ++p;
  41.         while ((*p++ = *s++));
  42.         tidied = 1;
  43.     }
  44.     while (NULL != (p = strstr(path,"/../"))) {
  45.         for (s = p+3; p != path && *--p != '/';);
  46.         if (*p != '/')
  47.             break;
  48.         if (p == path) 
  49.             ++p;
  50.         while ((*p++ = *s++));
  51.         tidied = 1;
  52.     }
  53.     while (NULL != (p = strstr(path,"//")) && *(p+2)) {
  54.         while ((*p = *(p+1))) ++p;
  55.         tidied = 1;
  56.     }
  57.     p = path + strlen(path);
  58.     if (*(p-1) == '/')
  59.         *--p = '\0';    /* remove tmp trailing slash */
  60.     while (--p != path && *p == '/') {    /* remove any others */
  61.         *p = '\0';
  62.         tidied = 1;
  63.     }
  64.     if (!strncmp(path,"./",2)) {
  65.         for (p = path, s = path+2; (*p++ = *s++););
  66.         tidied = 1;
  67.     }
  68.     return tidied;
  69. }
  70.  
  71. void fix_symlink (char *path, dev_t my_dev)
  72. {
  73.     static char lpath[PATH_MAX], new[PATH_MAX];
  74.     char *p, *np, *lp, *tail, *msg;
  75.     struct stat stbuf;
  76.     int c, fix_abs = 0, fix_messy = 0;
  77.  
  78.     if ((c = readlink(path, lpath, sizeof(lpath))) == -1) {
  79.         perror(path);
  80.         return;
  81.     }
  82.     lpath[c] = '\0';    /* readlink does not null terminate it */
  83.  
  84.     /* construct the absolute address of the link in new */
  85.     new[0] = '\0';
  86.     if (lpath[0] != '/') {
  87.         strcat(new,path);
  88.         if (((c = strlen(new)) > 0) && (new[c-1] == '/'))
  89.             new[c-1] = '\0';
  90.         if ((p = strrchr(new,'/')) != NULL)
  91.             *p = '\0';
  92.         strcat(new,"/");
  93.     }
  94.     strcat(new,lpath);
  95.  
  96.     /* check for various things */
  97.     if (stat(new, &stbuf) == -1) {
  98.         printf("dangling: %s -> %s\n", path, lpath);
  99.         if (delete) {
  100.             if (unlink (path))
  101.                 perror(path); 
  102.             else
  103.                 printf("deleted:  %s -> %s\n", path, lpath);
  104.         }
  105.         return;
  106.     }
  107.     if (stbuf.st_dev != my_dev) {
  108.         msg = "other_fs:";
  109.     } else if (lpath[0] == '/') {
  110.         msg = "absolute:";
  111.         fix_abs = 1;
  112.     } else if (verbose) {
  113.         msg = "relative:";
  114.     } else
  115.         msg = NULL;
  116.     fix_messy = tidy_path(strcpy(new,lpath));
  117.     if (fix_messy && !fix_abs)
  118.         msg = "messy:   ";
  119.     if (msg != NULL)
  120.         printf("%s %s -> %s\n", msg, path, lpath);
  121.     if (!fix_links || !(fix_messy || fix_abs))
  122.         return;
  123.  
  124.     if (fix_abs) {
  125.         /* convert an absolute link to relative: */
  126.         /* point tail at first part of lpath that differs from path */
  127.         /* point p    at first part of path  that differs from lpath */
  128.         (void) tidy_path(lpath);
  129.         tail = lp = lpath;
  130.         p = path;
  131.         while (*p && (*p == *lp)) {
  132.             if (*lp++ == '/') {
  133.                 tail = lp;
  134.                 while (*++p == '/');
  135.             }
  136.         }
  137.  
  138.         /* now create new, with "../"s followed by tail */
  139.         np = new;
  140.         while (*p) {
  141.             if (*p++ == '/') {
  142.                 *np++ = '.';
  143.                 *np++ = '.';
  144.                 *np++ = '/';
  145.                 while (*p == '/') ++p;
  146.             }
  147.         }
  148.         strcpy (np, tail);
  149.         (void) tidy_path(new);
  150.     }
  151.     if (unlink (path)) {
  152.         perror(path);
  153.         return;
  154.     }
  155.     if (symlink(new, path)) {
  156.         perror(path);
  157.         return;
  158.     }
  159.     printf("changed:  %s -> %s\n", path, new);
  160. }
  161.  
  162. void dirwalk (char *path, int pathlen, dev_t dev)
  163. {
  164.      char *name;
  165.     DIR *dfd;
  166.     static struct stat st;
  167.     static struct direct *dp;
  168.  
  169.     if ((dfd = opendir(path)) == NULL) {
  170.         perror(path);
  171.         return;
  172.     }
  173.  
  174.     name = path + pathlen;
  175.     if (*(name-1) != '/')
  176.         *name++ = '/'; 
  177.  
  178.     while ((dp = readdir(dfd)) != NULL ) {
  179.         strcpy(name, dp->d_name);
  180.                 if (strcmp(name, ".") && strcmp(name,"..")) {
  181.             if (lstat(path, &st) == -1) {
  182.                 perror(path);
  183.             } else if (st.st_dev == dev) {
  184.                 if (S_ISLNK(st.st_mode)) {
  185.                     fix_symlink (path, dev);
  186.                 } else if (recurse && S_ISDIR(st.st_mode)) {
  187.                     dirwalk(path, strlen(path), dev);
  188.                 }
  189.             }
  190.         }
  191.     } 
  192.     closedir(dfd);
  193.     path[pathlen] = '\0';
  194. }
  195.  
  196. void usage_error (void)
  197. {
  198.     fprintf(stderr, progver, progname);
  199.     fprintf(stderr, "Usage:\t%s [-crv] dirlist\n\n", progname);
  200.     fprintf(stderr, "Flags:\t-c == change absolute/messy links to relative\n\t-d == delete dangling links\n\t-r == recurse into subdirs\n\t-v == verbose (show all symlinks)\n\n");
  201.     exit(1);
  202. }
  203.  
  204. void main(int argc, char **argv)
  205. {
  206.     static char path[PATH_MAX+2], cwd[PATH_MAX+2];
  207.     int dircount = 0;
  208.     char c, *p;
  209.  
  210.     if  ((progname = (char *) strrchr(*argv, '/')) == NULL)
  211.                 progname = *argv;
  212.         else
  213.                 progname++;
  214.  
  215.     if (NULL == getcwd(cwd,PATH_MAX) || *cwd == '\0') {
  216.         fprintf(stderr,"getcwd() failed\n");
  217.         exit (1);
  218.     }
  219.     if (cwd[strlen(cwd)-1] != '/')
  220.         strcat(cwd,"/");
  221.  
  222.     while (--argc) {
  223.         p = *++argv;
  224.         if (*p == '-') {
  225.             if (*++p == '\0')
  226.                 usage_error();
  227.             while ((c = *p++)) {
  228.                      if (c == 'v')    verbose   = 1;
  229.                 else if (c == 'c')    fix_links = 1;
  230.                 else if (c == 'r')    recurse   = 1;
  231.                 else if (c == 'd')    delete    = 1;
  232.                 else            usage_error();
  233.             }
  234.         } else {
  235.             struct stat st;
  236.             if (*p == '/')
  237.                 *path = '\0';
  238.             else
  239.                 strcpy(path,cwd);
  240.             tidy_path(strcat(path, p));
  241.             if (lstat(path, &st) == -1)
  242.                 perror(path);
  243.             else
  244.                 dirwalk(path, strlen(path), st.st_dev);
  245.             ++dircount;
  246.         }
  247.     }
  248.     if (dircount == 0)
  249.         usage_error();
  250.     exit (0);
  251. }
  252.